
jQuery.ajaxSettings.traditional = true;

var Map = {

    size: {
        width: null,
        height: null
    },
    
    params: {
        refresh: 60*1000
    },
    
    _overload: 10,

    _data: {},
    _loaded: {},
    _askRefresh: false,
    _refreshing: false,
    _askSync: false,
    _synchronizing: false,
    _ground: null,
    _nextRefresh: null,
    _kingSquare: null,
    _kingData: null,
    _info: null,
    _pos: {
        left: 0,
        top: 0
    },
    _dim: {
        width: 0,
        height: 0
    },
    _timeout: null,
    _squareOver: null,
    _toolsReduced: false,

    init: function() {
    
        $('.Map .Right.Border').click( function() {
            var tools = $('.Tools' );
            if( Map._toolsReduced ) {
                $('.Map').css( 'right', tools.width() ); 
                Map.refreshMapDimensions();
                tools.animate( {
                    right: 0
                } );
                Map._toolsReduced = false;
            }
            else {
                tools.animate( {
                    right: -tools.width()
                }, function() {
                    $('.Map').css( 'right', '0px' );
                    Map.refreshMapDimensions();
                } );
                Map._toolsReduced = true;
            }
        } );
        
        $(window).bind( 'resize', function() {
            Map.refreshMapDimensions();
            Map.refreshPeriodically();
        });

        if (this._ground == null) {
            this._ground = $('.Ground');
            this.refreshSquaresSize();
            this._ground.draggable({

                start: function() {
                    $('.Map').css( 'cursor', '-moz-grabbing' );
                },
                stop: function() {
                    $('.Map').css( 'cursor', '-moz-grab' );
                },
                drag: function() {

                    Map.refreshPeriodically();
                }
            });
        }

        var pos = Logic.king.position;
        
        this.refreshMapDimensions();

        Map._pos = {
            left: Math.ceil(pos.x - Map._dim.width / 2),
            top: Math.ceil(pos.y - Map._dim.height / 2)
        };
        
        this.zoom.init();
        
        Map.synchronize( function() {
            $('#Loader').remove();
        });
    },
    
    goToPoint: function( point ) {
        var rect = this._getVisibleRectangle();
        var offset = this._ground.offset();
        var moveX = point.x - Math.floor(rect.width/2) - rect.x;
        var moveY = point.y - Math.floor(rect.height/2) - rect.y;

        this._ground.css( {
            left : offset.left - moveX * this.size.width,
            top : offset.top - moveY * this.size.height
        }, 5000 );
        
        Map.refresh();
    },
    
    refreshMapDimensions: function() {
        var width = this._ground.parent().width();
        var height = this._ground.parent().height();

        Map._dim = {
            width: Math.ceil(width / this.size.width),
            height: Math.ceil(height / this.size.height)
        }
    },
    
    refreshSquaresSize: function() {
        var testSquare = $('<div class="Square"></div>');
        this._ground.append( testSquare );
        Map.size.width = testSquare.outerWidth() - 1;
        Map.size.height = testSquare.outerHeight() - 1;
        testSquare.remove();
        Map.refreshMapDimensions();
    },
    
    refreshSquaresPosition: function() {
        for( var key in Map._loaded ) {
            var square = Map._loaded[key];
            var x = square.attr( 'x' );
            var y = square.attr( 'y' );
            square.css({
                top: (y - Map._pos.top) * Map.size.height,
                left: (x - Map._pos.left) * Map.size.width
            });
        }
    },

    refresh: function() {

        if (this._refreshing) {
            this._askRefresh = true;
            return;
        }

        this._askRefresh = false;
        this._refreshing = true;

        this._refresh();

        this._refreshing = false;
        if (this._askRefresh) {
            Map.refresh();
        }
    },

    refreshPeriodically: function() {
        var o = this;
        if (this._timeout == null) {
            this._timeout = setTimeout(function() {
                Map.refresh();
                o._timeout = null;
            }, 500);
        }
    },

    load: function(rectangles, callback) {

        var rects = [];
        for (var i = 0; i < rectangles.length; i++) {
            rects.push(Tools.rectangle.toString(rectangles[i]));
        }

        if( Map._nextRefresh ) {
            clearTimeout( Map._nextRefresh );
        }

        $.post('Game/SynchronizeMap', { rectangles: rects,
            sessionId : Logic.globals.sessionId }, function( json ) {
            Map.handleSynchronization(json);
            if( callback ) {
                callback( json );
            }
        }, 'json');
    },
    
    handleSynchronization:  function(json) {
        try {
            var time = new Date().getTime();
            for (var i = 0; i < json.Squares.length; i++) {
                // X, Y, HasKing, Troops, KingId
                var square = json.Squares[i].split(',');
                var x = parseInt(square[0]);
                var y = parseInt(square[1]);

                Map._data[x + ',' + y] = {
                    nickname: square[5],
                    kingId: square[4] === '' ? null : parseInt(square[4]),
                    troops: square[3] === '' ? null : parseInt(square[3]),
                    hasKing: square[2] == '' ? null : parseInt(square[2]),
                    x: x,
                    y: y,
                    time: time
                };
                
                try {
                    Map.square._refreshOrCreatePoint(y, x);
                }
                catch (e) {}
                
            }
            
            if( Map._nextRefresh ) {
                clearTimeout( Map._nextRefresh );
            }
            
            Map._nextRefresh = setTimeout( function() {
                Map.synchronize();
            }, Map.params.refresh );
        }
        catch(e) {
            
        }
    },

    synchronize: function() {
        if (this._synchronizing) {
            this._askSync = true;
            return;
        }

        this._askSync = false;
        this._synchronizing = true;

        this._synchronize( function() {
        
            Map._synchronizing = false;
            if (Map._askSync) {
                Map.synchronize();
            }
            
        } );

    },
    
    _synchronize: function( callback ) {
        Map.load([this._getVisibleRectangle()], callback);
    },

    _getVisibleRectangle: function() {

        var offset = this._ground.offset();
        var left = Map._pos.left - Math.ceil(offset.left / this.size.width) - Map._overload;
        var top = Map._pos.top - Math.ceil(offset.top / this.size.height) - Map._overload;

        return {
            x: left,
            y: top,
            width : Map._dim.width + 2 * Map._overload,
            height: Map._dim.height + 2 * Map._overload
        };
    },

    _refresh: function() {

        var rect = this._getVisibleRectangle();
        var needSync = false;

        for (var i = 0; i <= rect.height; i++) {
            for (var j = 0; j <= rect.width; j++) {
                if (!Map.square._checkPoint(i + rect.y, j + rect.x)) {
                    needSync = true;
                    break;
                }
            }
        }

        if (needSync) {
            Map.synchronize();
        }
    },

    square: {
    
        _selected : null,

        _createPoint: function(y, x) {

            var key = x + ',' + y;
            var square = Map._loaded[key];
            if (!square) {
                square = $('<div class="Square"></div>');
                Map.square._initPoint(y, x, square);
                Map._loaded[key] = square;
                Map._ground.append(square);
                Map.square._refreshPoint(y, x, square);
            }
        },

        _refreshOrCreatePoint: function(y, x) {

            var key = x + ',' + y;
            var square = Map._loaded[key];
            if (!square) {
                Map.square._createPoint(y, x);
            }
            else {
                Map.square._refreshPoint(y, x, square);
            }
        },

        _checkPoint: function(y, x) {
            var key = x + ',' + y;
            var data = Map._data[key];
            if (!data) {
                return false;
            }
            return data.time > (new Date().getTime() - 60 * 1000);
        },
        
        _initPoint: function(y, x, square) {
        
            var key = x + ',' + y;
            var data = Map._data[key];
            square.css({
                top: (y - Map._pos.top) * Map.size.height,
                left: (x - Map._pos.left) * Map.size.width
            });
            square.attr('x', x);
            square.attr('y', y);
            
            var func = function( e ) {
                e.preventDefault();
                var data = Map._data[key];
                if( Logic.king.academyTroops ) {
                    Dialog.displayTroopsSender( data );
                }
                return false;
            }
            
            square.hover( this._mouseOver, this._mouseOut );
            
            square.bind( 'contextmenu', func );
            square.bind( 'click', function(e) {
                if( Logic.actions.moveKing.enabled ) {
                    if( ((Logic.king.position.x == data.x 
                        && Math.abs(data.y - Logic.king.position.y) == 1)
                        || (Logic.king.position.y == data.y 
                        && Math.abs(data.x - Logic.king.position.x) == 1))
                        && (data.kingId == Logic.king.id) ) {
                        Dialog.displayMoveKingConfirmation( data );
                    }
                    
                }
                if( Logic.actions.sendTroops.enabled ) {
                    Dialog.displayTroopsSender( data );
                }
            } );
        },
        
        _mouseOver: function( e ) {
        
            if( Map._info ) {
                Map._info.remove();
                Map._info = null;
            }
            
            var key = $(this).attr( 'x' ) + ',' + $(this).attr( 'y' );
            var data = $(this).data( 'data' );
            var incomings = Logic.attacks.incoming._incomingAttacks[key];
            var ongoings = Logic.attacks.ongoing._ongoingAttacks[key];
            
            if( !data.nickname && !incomings && !ongoings && !data.troops ) {
                return;
            }
            if( data.nickname && Logic.actions.viewTerritories.enabled ) {
                $('.Visible').removeClass( 'Visible' );
                $('.Square[kingId=' + data.kingId + ']').addClass( 'Visible' );
                //$('.Overlay').show();
            }
            
            //Logic.actions.sendTroops.path.mouseover.call( this );
            
            var nickname = data.nickname ? data.nickname : 'neutral';

            var info = $('<div class="ContextInfo"><dl></dl></div>');
            info.append( '<dt>Owner:</dt><dd>' + nickname + '</dt>' );
            
            if( data.troops ) {
                  info.append( '<dt>Troops:</dt><dd>' + data.troops + '</dt>' );
            }
            
            
            
            var code = '<dt>Incoming attacks:<br /></dt><dd><ul>';
            if( incomings ) {
                for( var i in incomings ) {
                    var incoming = incomings[i];
                    code += '<li>Attack ' + Tools.date.toHuman(incoming.ArrivalDate) + ' by ' + incoming.SenderName + '</li>';
                    
                }
                info.append( code + '</ul></dd>' );
            }
            
            
            
            var code = '<dt>Ongoing attacks:<br /></dt><dd><ul>';
            if( ongoings ) {
                for( var i in ongoings ) {
                    var ongoing = ongoings[i];
                   code += '<li>' + (data.kingId == Logic.king.id ? 'Reinforcement' : 'Attack') + Tools.date.toHuman(ongoing.ArrivalDate) + ' with ' + ongoing.TroopsNumber + ' troops.</li>';
                    
                }
                info.append( code + '</ul></dd>' );
            }
           
            
            var offset = {
                left: (this.offsetLeft + Map.size.width + 10),
                top: (this.offsetTop + Map.size.height + 10)
            };
            info.css( offset );
            Map._info = info;
            Map._ground.append( info );
            
            var groundOffset = Map._ground.offset();

            if( ((offset.left + info.width()) >= (-groundOffset.left + Map._dim.width*Map.size.width - 50))
                ||  ((offset.top + info.height()) >= (-groundOffset.top + Map._dim.height*Map.size.height - 50)) ) {
                offset.left -= info.width() + Map.size.width + 30;
                offset.top -= info.height() + Map.size.height + 30;
                info.css( offset );
            }
            
        },
        
        _mouseOut: function() {
            //Logic.actions.sendTroops.path.mouseout.call( this );
            if( Map._info ) {
                Map._info.remove();
                Map._info = null;
            }
            
            if( Logic.actions.viewTerritories.enabled ) {
                $('.Visible').removeClass( 'Visible' );
                //$('.Overlay').hide();
            }
        },

        _refreshPoint: function(y, x, square) {

            var key = x + ',' + y;
            if (!Map._data[key]) {
                return;
            }

            var data = Map._data[key];
            square.data( 'data', data );
            
            square.attr( 'kingId', data.kingId );
            
            // Color
            if (data.kingId == Logic.king.id) {
                square.addClass('Me').removeClass('NotMe');
                if( !data.hasKing ) {
                    var coeff = Math.min(data.troops/200,1);
                    var coeff = Math.round(coeff*20)*5;
                    square.attr( 'strong', "" + coeff );
                }
                else {
                    //squere.removeAttr( 'strong' );
                }
            }
            else {
                square.removeAttr( 'strong' );
                if (data.kingId) {
                    square.addClass('NotMe').removeClass('Me');
                }
                else {
                    square.removeClass('NotMe').removeClass( 'Me' );
                }
            }

            // Incoming attacks
            var incomings;
            if(incomings = Logic.attacks.incoming._incomingAttacks[key]) {
                var noIncoming = true;
                for( var i in incomings ) {
                    var incoming = incomings[i];
                    if( incoming.ArrivalDate.getTime() < new Date().getTime() ) {
                        square.incoming.remove();
                        delete square.incoming;
                    }
                    else {
                        noIncoming = false;
                        break;
                    }
                }
                if( noIncoming && square.incoming ) {
                    square.incoming.remove();
                    delete square.incoming;
                }
                else if( !noIncoming && !square.incoming ) {
                    square.incoming = $('<div class="Incoming"></div>');
                    square.append(square.incoming);
                }
            }
            else if( square.incoming ) {
                square.incoming.remove();
                delete square.incoming;
            }
            
            // Ongoing attacks
            var ongoings;
            if(ongoings = Logic.attacks.ongoing._ongoingAttacks[key]) {
                var noOngoing = true;
                for( var i in ongoings ) {
                    var ongoing = ongoings[i];
                    if( ongoing.ArrivalDate.getTime() < new Date().getTime() ) {
                        square.ongoing.remove();
                        delete square.ongoing;
                    }
                    else {
                        noOngoing = false;
                        break;
                    }
                }
                if( noOngoing && square.ongoing ) {
                    square.ongoing.remove();
                    delete square.ongoing;
                }
                else if( !noOngoing && !square.ongoing ) {
                    square.ongoing = $('<div class="Ongoing"></div>');
                    square.append(square.ongoing);
                }
            }
            else if( square.ongoing ) {
                square.ongoing.remove();
                delete square.ongoing;
            }
            
            var left = (data.x - 1) + ',' + data.y;
            var top = data.x + ',' + (data.y-1);
            square.css( 'border-left-color', ( Map._data[left] && (Map._data[left].kingId !== data.kingId)) ? '#777' : null );
            square.css( 'border-top-color', ( Map._data[top] && (Map._data[top].kingId !== data.kingId)) ? '#777' : null );
            var right = (data.x + 1) + ',' + data.y;
            var bottom = data.x + ',' + (data.y + 1);
            if( Map._loaded[right] ) {
                Map._loaded[right].css( 'border-left-color', ( Map._data[right].kingId !== data.kingId) ? '#777' : null );
            }
            if( Map._loaded[bottom] ) {
                Map._loaded[bottom].css( 'border-top-color', ( Map._data[bottom].kingId !== data.kingId) ? '#777' : null );
            }
            
            // King in position
            if (data.hasKing) {
                square.addClass('WithKing');
                if( data.kingId == Logic.king.id ) {
                    Map._kingSquare = square;
                    Map._kingData = data;
                    Logic.actions.takeTroops.refresh();
                }
            }
            else {
                square.removeClass('WithKing');
            }
            
            // Troops
            if (data.troops === null) {
                square.troops.remove();
                delete square.troops;
                square.removeClass('WithTroops');
            }
            else {
                square.addClass('WithTroops');
                if (!square.troops) {
                    square.troops = $('<div class="Troops"></div>');
                    square.append(square.troops);
                }
                square.troops.html(data.troops);
            }
        }

    },
    
    zoom : {
    
        current: 1,
        defaultSize: 50,
    
        init: function() {
            $('.ZoomIn').click(function() {
                if( $(this).hasClass( 'Disabled' ) ) {
                    return;
                }
                Map.zoom.setZoom(Map.zoom.current/2);
            } );
            
            $('.ZoomOut').click(function() {
                if( $(this).hasClass( 'Disabled' ) ) {
                    return;
                }
                Map.zoom.setZoom(Map.zoom.current*2);
            } );
        
        },
        
        setZoom: function(zoom) {
            var size = Math.round(zoom * Map.zoom.defaultSize);
            this.current = zoom;
            $('.ZoomIn')[ zoom <= 0.5 ? 'addClass' : 'removeClass' ]( 'Disabled' );
            $('.ZoomOut')[ zoom >= 2 ? 'addClass' : 'removeClass' ]( 'Disabled' );
            $('style').html( '.Square { width : ' + size + 'px; height: ' + size + 'px }' );
            if( zoom < 1  ) {
                $('style').append( '.Square .Troops { display: none } ' );
            }
            Map.refreshSquaresSize();
            Map.refreshSquaresPosition();
            Map.synchronize();
        }
    
    }

};
